package cn.tedu.review;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/*本类用于复写售票案例实现方案2*/
public class TestRunnable {     //测试类
    public static void main(String[] args) {
        //4.创建自定义类对象,作为唯一的业务对象
        TicketRunnable target = new TicketRunnable();
        //5.创建多个线程对象,并且把唯一的业务对象交给线程对象来干活
//        Thread t1 = new Thread(target);
//        Thread t2 = new Thread(target);
//        Thread t3 = new Thread(target);
//        Thread t4 = new Thread(target);
        //6.以多线程的方式启动线程//多线程方式启动线程
//        t1.start();
//        t2.start();
//        t3.start();
//        t4.start();
        /*Executors是用来辅助创建线程池的工具类对象  //减少代码冗余度
        * */
        ExecutorService pool = Executors.newFixedThreadPool(5); //1)把池子创建出来,2)池子里,最多5个线程
        for (int i = 0; i < 4; i++) {
            pool.execute(target);  //传入唯一业务对象
        }      //线程池只有锁对象,没有if并列,超卖和重卖都有问题,misunder

    }
}

/*1.多线程出现数据安全问题的原因:多线程程序+共享数据+多条语句操作共享数据*/
/*2.同步锁:相当于给容易出现问题的代码加了一把锁,包裹了所有可能会出现数据安全的代码
 * 加锁之后,就有了同步(排队)的效果,加锁需要考虑:
 * 锁的范围:不能太大,太大,干啥都得排队,效率低
 *         不能太小,太小,锁不住,还是会出现安全隐患
 * 并且注意!!!多个线程间,必须使用同一把锁,否则锁不住!!!*/
//1.自定义多线程售票类
class TicketRunnable implements Runnable {      //物料类
    //3.完成业务
    int tickets = 100;
//    ticket = 3;
//    Object o = new Object(); //只有一个
    Cat c = new Cat();

    //2.添加接口中未实现的方法,里面是我们的业务
    @Override
    public void run() {
        while (true) {
            /*tickets=3369;
            int a;
            a = 3;*/
            /*3.同步代码块:synchronized(唯一的锁对象){会出现安全隐患的所有代码}
             * 同步代码块在同一时刻,同一资源只会被一个线程对象独享*/ //刚刚每次只能一个线程进去

            /*这种写法不对,相当于每个线程进来时,执行这句话都会new一个新的锁对象
             * 多个线程间使用的并不是同一个唯一的锁对象,所以锁不住*///不是唯一的锁对象
            synchronized (c) { //锁不住//匿名多个对象,,,
            //修改同步代码块的锁对象为成员变量o,因为锁对象必须唯一
//            synchronized (o) {//同步代码块解决的是重卖的问题 //锁得住
//            synchronized (c) {//同步代码块解决的是重卖的问题 //锁得住
//            synchronized (TicketRunnable.class) {//同步代码块解决的是重卖的问题 //锁得住  //中大逻辑解决重卖:TicketRunnable.class,保证线程挨个同步进入窗口就绪状态
//            synchronized (c) {//同步代码块解决的是重卖的问题 //锁得住  //中大逻辑解决重卖:TicketRunnable.class,保证线程挨个同步进入窗口就绪状态
                if (tickets > 0) {           // 中大逻辑: 保证票数1只能被一个线程获取
                    //7.让线程休眠,增加出错概率
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":" + tickets--);
                }
                if (tickets <= 0) break;  //粗粒度,1)避免一张票多个线程拿到,防止重卖(鱼贯而入); 2)并列if就是解决超卖情况(票数为0,就退出当前线程),,,,eg, 中粒度:bingfa
            //customized PS1: 1)加了唯一锁之后 (), 2)鱼贯而入,票源充足时,不会发生抢票重卖现象 3)只剩一张票时,即要加同步唯一锁,也要写并列if,因为其它线程没有资源后,就不会排队,全力抢占最后一个票(电子脉冲)
            //customized PS2: 1)本来一开始就在抢着打盒饭,加了唯一锁就会各自排序打饭;2)但是只有一个盒饭时,又出现请盒饭,超卖盒饭,3)然后并列if后,就会阻止超卖现象了
            }
        }
    }
}

class Cat{

}